package com.pig4cloud.pigx.contract.api.v1.websocket.subscribe;

import com.alibaba.fastjson.JSONObject;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.customize.api.enums.AbnormalEnum;
import com.pig4cloud.pigx.common.customize.api.exception.OpenApiException;
import com.pig4cloud.pigx.common.customize.i18n.util.MessageUtils;
import com.pig4cloud.pigx.common.websocket.holder.SessionKeyGenerator;
import com.pig4cloud.pigx.contract.api.v1.service.impl.OrderServiceImplV1;
import com.pig4cloud.pigx.contract.api.v1.utils.OpenApiContractUtilsV1;
import com.pig4cloud.pigx.contract.api.v1.websocket.message.OpenApiSendMessageV1;
import com.pig4cloud.pigx.contract.api.v1.websocket.vo.OpenApiAbstractTopicVOV1;
import com.pig4cloud.pigx.contract.entity.ContractKLine;
import com.pig4cloud.pigx.contract.mongo.entity.ContractSymbolMongo;
import com.pig4cloud.pigx.contract.open.api.dto.OpenApiOrderBookDTOV1;
import com.pig4cloud.pigx.contract.open.api.vo.OpenApiOrderBookVOV1;
import com.pig4cloud.pigx.contract.utils.ContractUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 */
@Slf4j
@Component
public class OpenApiBestOrderV1 extends RequestDataAbstractTopicV1 {

	private final OpenApiContractUtilsV1 apiContractUtils;

	private final ContractUtils contractUtils;

	private final OrderServiceImplV1 orderService;

	private final SessionKeyGenerator sessionKeyGenerator;

	public static final String API_NAME = "best_order";

	public OpenApiBestOrderV1(OpenApiContractUtilsV1 apiContractUtils, ContractUtils contractUtils, OrderServiceImplV1 orderService, SessionKeyGenerator sessionKeyGenerator) {
		this.apiContractUtils = apiContractUtils;
		this.contractUtils = contractUtils;
		this.orderService = orderService;
		this.sessionKeyGenerator = sessionKeyGenerator;
		init();
	}

	private void init() {
		wsPush();
	}

	private void wsPush() {
		ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
		service.scheduleAtFixedRate(() -> {
			// 记录请求参数不合法的session,发送一次报错信息后,移除session队列
			List<WebSocketSession> requestErrorList = new ArrayList<>();
			List<WebSocketSession> symbolErrorList = new ArrayList<>();
			for (Map.Entry<WebSocketSession, OpenApiAbstractTopicVOV1> entry : subList.entrySet()) {
				if (!entry.getKey().isOpen()) {
					subList.remove(entry.getKey());
					log.info("ws 移除已关闭的session");
					continue;
				}
				try {
					// 开始参数校验
					JSONObject param = entry.getValue().getData().getRequestParam();
					OpenApiOrderBookDTOV1 dto = JSONObject.parseObject(param.toJSONString(), OpenApiOrderBookDTOV1.class);
					if (dto == null
							|| dto.getSymbolName() == null
							|| dto.getIsBuy() == null
							|| dto.getSymbolName().isEmpty()
							|| dto.getIsBuy().isEmpty()
					) {
						// 必填参数为空发送异常消息
						entry.getKey().sendMessage(OpenApiSendMessageV1.getTextMessage(R.failed(
								AbnormalEnum.MSG.MANDATORY_PARAM_EMPTY_OR_MALFORMED.getCode(),
								MessageUtils.get(AbnormalEnum.MSG.MANDATORY_PARAM_EMPTY_OR_MALFORMED.getMessage()))
						));
						requestErrorList.add(entry.getKey());
						continue;
					}

					String symbolName = dto.getSymbolName();
					String isBuy = dto.getIsBuy();
					BigDecimal price = dto.getPrice();

					// 币对校验
					ContractSymbolMongo mongo;
					try {
						// 币对校验
						mongo = apiContractUtils.getSymbolMongo(symbolName);
						OpenApiOrderBookDTOV1 vo = new OpenApiOrderBookDTOV1();
						// 获取用户id
						Object userId = sessionKeyGenerator.sessionKey(entry.getKey());
						if (userId == null) {
							throw new OpenApiException(
									AbnormalEnum.MSG.OPTIONS_USER_NOT_FOUND.getCode(),
									MessageUtils.get(AbnormalEnum.MSG.OPTIONS_USER_NOT_FOUND.getMessage())
							);
						}
						vo.setUserId(Long.valueOf(userId.toString()));
						vo.setSymbolName(symbolName);
						vo.setIsBuy(isBuy);
						if (price == null) {
							price = mongo.getIndexPrice();
						}
						vo.setPrice(price);
						OpenApiOrderBookVOV1 data;
						try {
							data = orderService.getOrderBook(vo).getData();
							if (data != null) {
								contractUtils.setScaleBySymbol(data,data.getSymbolName());
							}
						} catch (Exception e) {
							throw new OpenApiException(
									AbnormalEnum.MSG.DISCONNECTED.getCode(),
									MessageUtils.get(AbnormalEnum.MSG.DISCONNECTED.getMessage())
							);
						}
						// 发送消息
						try {
							// 发送最优挂单
							entry.getKey().sendMessage(OpenApiSendMessageV1.getTextMessage(
									R.ok(data)
							));
						} catch (IOException exception) {
							throw new RuntimeException(exception);
						}
					} catch (OpenApiException e) {
						// 返回异常消息
						try {
							// 将捕获的异常消息发送
							entry.getKey().sendMessage(OpenApiSendMessageV1.getTextMessage(
									R.failed(e.getCode(), e.getMessage())
							));
							symbolErrorList.add(entry.getKey());
						} catch (IOException exception) {
							throw new RuntimeException(exception);
						}
					}

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			// 移除请求参数异常的session
			for (WebSocketSession session : requestErrorList) {
				unSub(session);
			}
			// 移除请求无效的session
			for (WebSocketSession session : symbolErrorList) {
				unSub(session);
			}
		},0, 500, TimeUnit.MILLISECONDS);
	}

}
